﻿using AJWPFAdmin.Core.Enums;
using AJWPFAdmin.Core.Models;
using AJWPFAdmin.Core.Models.EF.Tables;
using AJWPFAdmin.Core.Utils;
using AJWPFAdmin.Services.EF;
using Masuit.Tools.Reflection;
using MaterialDesignThemes.Wpf;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json.Linq;
using Prism.Ioc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace AJWPFAdmin.Services.AppointAPI
{
    public class BinZhouAppointAPI : AppointAPIBase
    {
        private APIConfig _apiConfig;

        private static readonly string[] _imageFields = new[] { "carImgBase64", "certificateImgBase64",
            "inventoryImgBase64", };

        public BinZhouAppointAPI(ApplicationType appType,
            SystemConfigDictionary cfg,
            IContainerProvider svcProvider) : base(appType, cfg, svcProvider)
        {

        }
        protected override void OnAPILogsRaised(PassagewayDirection? direction,
            string logs)
        {
            base.OnAPILogsRaised(direction, logs);
        }

        private async Task<ProcessResult> LoginAsync()
        {
            if (string.IsNullOrWhiteSpace(_apiConfig.Authorization)
                || DateTime.Now > _apiConfig.TokenExpireDate)
            {
                var loginRet = await PostAsync("/login", new JObject
                {
                    {"username", _apiConfig.Account },
                    {"password", _apiConfig.Password },
                }, null, needAuth: false);

                if (!loginRet.Success)
                {
                    return loginRet;
                }
                else
                {
                    _apiConfig.Authorization = (loginRet.Data as APIResponse).token.ToString();
                    _apiConfig.TokenExpireDate = DateTime.Now.AddMinutes(29);

                    loginRet.SetSuccess(_apiConfig.Authorization);
                    try
                    {
                        // 重新查出来保存登录token
                        using var db = DbService.GetDbContext(_configService);

                        Config = db.SystemConfigDictionaries.FirstOrDefault(p => p.Key == SystemConfigKey.APIBinZhou);

                        Config.StringValue = CommonUtil.AJSerializeObject(_apiConfig);
                        db.Entry(Config).State = EntityState.Modified;

                        db.SaveChanges();
                    }
                    catch (Exception)
                    {
                    }
                }
            }
            return new ProcessResult
            {
                Success = true,
                Data = _apiConfig.Authorization
            };
        }

        public override async Task<ProcessResult> UploadShippingRecordAsync(ShippingRecordParams @params)
        {
            ProcessResult result;
            var record = @params.Record;

            var carNo = record.CarNo;

            var response = new UploadShippingRecordResponse();

            var carType = (CarTypeEnum)((int)record.TypeId);

            // 超过固定车范围的不做操作
            if (carType > CarTypeEnum.进出厂车)
            {
                result = new ProcessResult();
                response.RecordNum++;
                result.SetSuccess();
                result.Attach = response;
                return result;
            }

            var time = record.Direction == PassagewayDirection.进
                ? record.ShipStartDate : record.ShipEndDate;

            var fakeCarInfo = new Car
            {
                Attachments = record.Attachments,
                VehicleLicense = record.VehicleLicense,
                EngineNameplate = record.EngineNameplate,
                Nameplate = record.Nameplate,
                MachineEnvProtectionLabel = record.MachineEnvProtectionLabel
            };

            var (carHead, _, carTail) = record.GetWatchPositionImageFile(record.Direction);

            var attach = fakeCarInfo.GetFileOfPropertyName(nameof(Car.Attachments));
            var licence = fakeCarInfo.GetFileOfPropertyName(nameof(Car.VehicleLicense));

            result = await PostAsync("/passLog/push", new JObject
            {
                {"carType", ((byte)record.PlateColor).ToString() },
                {"carNum", record.CarNo },
                {"fuelType", record.FuelTypeCode },
                {"emissionStandard", record.EmissionStandard.GetDescription() },
                {"gbpadbzx", record.Direction == PassagewayDirection.进 ? "1" : "2" },
                {"passTime", time.GetValueOrDefault().ToString("yyyy-MM-dd HH:mm:ss") },
                {"DPN", _apiConfig.DPN },
                {"USCC", _apiConfig.USCC },
                {"entranceGuardPosition", _apiConfig.EntranceGuardPosition },
                {"carImgBase64", CommonUtil.GetBase64FromLocalOrHttpFile(_carIdentificationConfig.CompleteFileUrl(carNo, carHead),compressTargetSize:95) },
                {"carImgName", Path.GetFileName(carHead) },
                {"certificateImgBase64",  CommonUtil.GetBase64FromLocalOrHttpFile(_carIdentificationConfig.CompleteFileUrl(carNo, licence),compressTargetSize:95)},
                {"certificateImgName",  Path.GetFileName(licence)},
                {"inventoryImgBase64",  CommonUtil.GetBase64FromLocalOrHttpFile(_carIdentificationConfig.CompleteFileUrl(carNo, attach),compressTargetSize:95)},
                {"inventoryImgName",  Path.GetFileName(attach)}
            }, null, needUILog: true, direction: record.Direction);

            if (!result.Success)
            {
                result.Attach = response;
                return result;
            }

            // 过车记录上传成功,记录号加1
            response.RecordNum++;
            result.Attach = response;

            return result;
        }

        private async Task<ProcessResult> PostAsync(
            string method,
            JObject body,
            Dictionary<string, string> query,
            bool isListResponse = false, bool needUILog = false,
            bool needAuth = true,
            PassagewayDirection? direction = null)
        {
            var result = new ProcessResult();

            StringBuilder stringBuilder = null;

            using var httpClient = CreateClient();

            try
            {

                stringBuilder = new StringBuilder();

                if (needAuth)
                {
                    result = await LoginAsync();

                    if (!result.Success)
                    {
                        return result;
                    }

                    httpClient.DefaultRequestHeaders
                        .TryAddWithoutValidation("Authorization", _apiConfig.Authorization);
                }

                var bodyStr = body == null ? "{}" : body.ToString(Newtonsoft.Json.Formatting.None);
                var queryStr = string.Empty;
                if (query?.Count > 0)
                {
                    queryStr = $"?{string.Join("&", query.Select(p => $"{p.Key}={HttpUtility.UrlEncode(p.Value)}"))}";
                }

                stringBuilder.Append($"{KeyDescription} {_apiConfig.APIUrl}{method}:\r\n");

                var logBody = new JObject();

                if (body != null)
                {
                    var props = body.Properties();
                    foreach (var prop in props)
                    {
                        if (_imageFields.Contains(prop.Name))
                        {
                            logBody.Add(prop.Name, prop.Value != null ? "图片数据" : prop.Value);
                        }
                        else
                        {
                            logBody.Add(prop.Name, prop.Value);
                        }
                    }
                }

                stringBuilder.Append($"请求body参数:{logBody.ToString()}\r\n");
                stringBuilder.Append($"请求查询参数:{queryStr}\r\n");

                var content = new StringContent(bodyStr, Encoding.UTF8, "application/json");

                var res = await httpClient.PostAsync($"{_apiConfig.APIUrl}{method}{queryStr}", content);

                var responseStr = await res.Content.ReadAsStringAsync();

                stringBuilder.Append($"接口响应源内容\r\n:{responseStr}");

                if (res.StatusCode == System.Net.HttpStatusCode.OK)
                {
                    var response = CommonUtil.TryGetJSONObject<APIResponse>(responseStr) ?? new APIResponse
                    {
                        code = -1,
                        msg = "解析接口返回失败",
                    };

                    if (response.code == 200)
                    {
                        result.SetSuccess(response);
                    }
                    else
                    {
                        result.SetError(response.msg);
                    }

                }
                else
                {
                    result.SetError($"接口访问失败:{res.StatusCode}");
                }

                var logContent = stringBuilder.ToString();
                _logger.Error(logContent);
                if (needUILog)
                {
                    OnAPILogsRaised(direction, logContent);
                }

            }
            catch (Exception e)
            {
                var logContent = e.Message;
                stringBuilder.Append($"{logContent}\r\n");
                result.SetError(logContent, e);
                if (stringBuilder != null)
                {
                    stringBuilder.Append(e.StackTrace);
                    _logger.Error(stringBuilder.ToString());
                }
                if (needUILog)
                {
                    OnAPILogsRaised(direction, stringBuilder.ToString());
                }
            }
            return result;
        }

        private HttpClient CreateClient()
        {
            var httpClient = new HttpClient();

            //httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", $"Bearer {_apiConfig.Token}");

            return httpClient;
        }

        public override Task ConvertToCustomConfig(bool isReal)
        {
            _apiConfig = CommonUtil.TryGetJSONObject<APIConfig>(Config.StringValue) ?? new APIConfig();
            _customAPIConfig = _apiConfig;
            AutoUploadDataVerification = _apiConfig.AutoUploadDataVerification;

            if (isReal)
            {
                //if (_appType == ApplicationType.岗亭端)
                //{

                //}
            }
            else
            {
                _ = GetSchemas();
            }

            return Task.CompletedTask;
        }

        public new void Dispose()
        {

        }

        public class APIConfig : APIConfigBase
        {
            [DynamicFormItemDefine("接口地址")]
            public string APIUrl { get; set; }

            [DynamicFormItemDefine("账号")]
            public string Account { get; set; }

            [DynamicFormItemDefine("密码")]
            public string Password { get; set; }

            [DynamicFormItemDefine("排污许可证")]
            public string DPN { get; set; }

            [DynamicFormItemDefine("企业统一社会信用代码")]
            public string USCC { get; set; }

            [DynamicFormItemDefine("门禁方位")]
            public string EntranceGuardPosition { get; set; }

            [DynamicFormItemDefine("登录认证Token", Disable = true)]
            public string Authorization { get; set; }

            [DynamicFormItemDefine("登录认证Token过期时间", Disable = true)]
            public DateTime TokenExpireDate { get; set; }

        }

        public class APIResponse
        {
            public int code { get; set; }
            public string msg { get; set; }
            public string token { get; set; }
        }
    }
}
